package com.xmlit.project.client;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;

import com.google.gwt.storage.client.Storage;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.RootPanel;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.ListGridFieldType;
import com.smartgwt.client.types.TextAreaWrap;
import com.smartgwt.client.types.TitleOrientation;
import com.smartgwt.client.types.TreeModelType;
import com.smartgwt.client.types.VerticalAlignment;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.Img;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.TransferImgButton;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.CheckboxItem;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.TextAreaItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
import com.smartgwt.client.widgets.form.validator.RegExpValidator;
import com.smartgwt.client.widgets.grid.events.SelectionChangedHandler;
import com.smartgwt.client.widgets.grid.events.SelectionEvent;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.layout.VStack;
import com.smartgwt.client.widgets.menu.IMenuButton;
import com.smartgwt.client.widgets.menu.Menu;
import com.smartgwt.client.widgets.menu.MenuItem;
import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent;
import com.smartgwt.client.widgets.tab.Tab;
import com.smartgwt.client.widgets.tab.TabSet;
import com.smartgwt.client.widgets.tab.events.TabSelectedEvent;
import com.smartgwt.client.widgets.tab.events.TabSelectedHandler;
import com.smartgwt.client.widgets.tree.Tree;
import com.smartgwt.client.widgets.tree.TreeGrid;
import com.smartgwt.client.widgets.tree.TreeGridField;
import com.smartgwt.client.widgets.tree.TreeNode;
import com.xmlit.project.engine.struct.Struct;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Main implements EntryPoint {
	private static int PK_COUNTER;

	public static final String Sequence = "Sequence";
	public static final String Choice = "Choice";
	public static final String Simple = "Simple";

	public static final String Delimiter = "Delimiter";
	public static final String Lookahead = "Lookahead";
	public static final String Not = "Not";

	public static final String Prefix = "Prefix";
	public static final String Suffix = "Suffix";
	public static final String Regex = "Regex";
	public static final String AllowedValues = "AllowedValues";
	public static final String AllowedChars = "AllowedChars";
	public static final String AllowedCharsType = "AllowedCharsType";

	public static final String minLength = "MinLength";
	public static final String maxLength = "MaxLength";

	public static final String Name = "Name";
	public static final String Name1 = "Name1";
	public static final String Min = "Min";
	public static final String Max = "Max";
	public static final String Type = "Type";
	public static final String mustFollow = "Delimiter must be followed by";
	public static final String mustNotFollow = "Delimiter must be followed by";

	TextItem delimiterItem = null;
	CheckboxItem advance = null;
	TextItem lookahead = null;
	CheckboxItem not = null;
	DynamicForm nonleaf = null;
	TabSet leafTabs = null;
	TreeNode copy = null;

	// TextItem prefixItem = null;
	// TextItem suffixItem = null;
	TextItem regexItem = null;
	SelectItem departmentItem = null;
	SelectItem divisionItem = null;

	final static Map<String, Map<String, String>> categoryMap = new HashMap<String, Map<String, String>>();
	final static Map<String, String[]> categoryMapReverse = new HashMap<String, String[]>();
	static Map<String, String> selected = null;

	public static final HashMap<String, String> allowedCharsVals = new HashMap<String, String>();
	static {
		allowedCharsVals.put("Alphabetic",
				"abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
		allowedCharsVals.put("Numeric", "+-01234567890.");
		allowedCharsVals
				.put("Alphanumeric",
						"+-01234567890.abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");

		categoryMap
				.put("Date-Time",
						toHashMap(new String[][] {
								{ "dd/mm/yyyy",
										"(0?[1-9]|[12][0-9]|3[01])[- /.](0?[1-9]|1[012])[- /.](19|20)?[0-9]{2}" },
								{ "yyyy-mm-dd",
										"(19|20)[0-9]{2}[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])" },
								{ "HH:MM:SS",
										" ([0-1]?\\d|2[0-3]):([0-5]?\\d):([0-5]?\\d)" } }));

		categoryMap
				.put("Web",
						toHashMap(new String[][] {
								{
										"Email",
										"(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])" },
								{
										"URL",
										"((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\\\\\))+[\\w\\d:#@%/;$()~_?\\+-=\\\\\\.&]*)" } }));

		categoryMap.put("Numbers", toHashMap(new String[][] {
				{ "Integer", "(\\+|-)?[0-9]*" },
				{ "Decimal", "(\\+|-)?[0-9]*(\\.[0-9]*)?" } }));

		for (String key : categoryMap.keySet()) {
			for (String inKey : categoryMap.get(key).keySet()) {
				categoryMapReverse.put(categoryMap.get(key).get(inKey),
						new String[] { key, inKey });
			}
		}

	}

	private static String[] getCategoryAndExpression(String reg) {
		return categoryMapReverse.get(reg);
	}

	private static Map<String, String> toHashMap(String[][] strings) {
		HashMap<String, String> result = new HashMap<String, String>();
		for (int i = 0; i < strings.length; i++)
			result.put(strings[i][0], strings[i][1]);

		return result;
	}

	private static String getAllowedCharsValsOrNull(String chars) {

		if (chars == null)
			return null;
		for (Map.Entry<String, String> entry : allowedCharsVals.entrySet()) {
			if (chars.equals(entry.getValue())) {
				return entry.getKey();
			}
		}

		return null;
	}

	private final UnmarshelServiceAsync unmarshelService = GWT
			.create(UnmarshelService.class);

	public void onModuleLoad() {

		GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {

			@Override
			public void onUncaughtException(Throwable e) {
				GWT.log("", e);

			}
		});

		createScreen();
		unmarshelService.ping(new AsyncCallback<String>() {

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onSuccess(String result) {
				// TODO Auto-generated method stub

			}
		});

	}

	private DynamicForm getProperties() {
		nonleaf = new DynamicForm();
		nonleaf.setTop(handleVertical(30));
		nonleaf.setWidth(handleHorizontal(250));

		nonleaf.setLeft(handleHorizontal(910));
		delimiterItem = new TextItem();
		delimiterItem.setTitle("Delimiter");
		delimiterItem.setRequired(true);
		delimiterItem.addChangedHandler(new ChangedHandler() {

			@Override
			public void onChanged(ChangedEvent event) {
				treeGrid.getSelectedRecord().setAttribute(Delimiter,
						delimiterItem.getValue());
			}

		});
		advance = new CheckboxItem();
		advance.setName("advance");
		advance.setTitle("Advance");
		advance.setRedrawOnChange(true);
		advance.setWidth(50);
		advance.setValue(false);
		advance.addChangeHandler(new ChangeHandler() {
			public void onChange(ChangeEvent event) {
				if ((Boolean) event.getValue()) {
					lookahead.show();
					not.show();
				} else {
					lookahead.hide();
					not.hide();
				}
			}
		});
		lookahead = new TextItem();
		lookahead.setTitle(mustFollow);
		lookahead.setRequired(true);

		lookahead.addChangedHandler(new ChangedHandler() {

			@Override
			public void onChanged(ChangedEvent event) {
				treeGrid.getSelectedRecord().setAttribute(Lookahead,
						lookahead.getValue());
			}

		});

		not = new CheckboxItem();
		not.setName("not");
		not.setTitle("Not");
		not.setRedrawOnChange(true);
		not.setWidth(50);
		not.setValue(false);
		not.addChangeHandler(new ChangeHandler() {
			public void onChange(ChangeEvent event) {
				treeGrid.getSelectedRecord().setAttribute(Not,
						(Boolean) event.getValue());
				if ((Boolean) event.getValue()) {
					lookahead.setTitle(mustNotFollow);
				} else {
					lookahead.setTitle(mustFollow);
				}
			}
		});

		/*
		 * prefixItem = new TextItem(); prefixItem.setTitle("Prefix");
		 * prefixItem.setRequired(true);
		 * 
		 * prefixItem.addChangedHandler(new ChangedHandler() {
		 * 
		 * @Override public void onChanged(ChangedEvent event) {
		 * treeGrid.getSelectedRecord().setAttribute(Prefix,
		 * prefixItem.getValue()); }
		 * 
		 * });
		 * 
		 * suffixItem = new TextItem(); suffixItem.setTitle("Suffix");
		 * suffixItem.setRequired(true);
		 * 
		 * suffixItem.addChangedHandler(new ChangedHandler() {
		 * 
		 * @Override public void onChanged(ChangedEvent event) {
		 * treeGrid.getSelectedRecord().setAttribute(Suffix,
		 * suffixItem.getValue()); }
		 * 
		 * });
		 */
		/*
		 * regexItem = new TextItem(); regexItem.setTitle("Regular Expression");
		 * regexItem.setRequired(true);
		 * 
		 * regexItem.addChangedHandler(new ChangedHandler() {
		 * 
		 * @Override public void onChanged(ChangedEvent event) {
		 * treeGrid.getSelectedRecord().setAttribute(Regex,
		 * regexItem.getValue());
		 * 
		 * }
		 * 
		 * });
		 */

		nonleaf.setFields(new FormItem[] { delimiterItem, advance, lookahead,
				not /*
					 * , prefixItem , suffixItem
					 */
		/* regexItem */});

		return nonleaf;
	}

	private HLayout getButtons() {
		HLayout topButtons = new HLayout();
		// topButtons.setShowEdges(true);
		topButtons.setShowResizeBar(true);
		topButtons.setTop(handleVertical(245));
		topButtons.setLeft(handleHorizontal(880));
		topButtons.setWidth((230));
		topButtons.setHeight((25));
		IMenuButton addChild = new IMenuButton("Add Child", getAddChildMenu());
		addChild.setWidth((80));

		// addChild.setTop(handleVertical(5);
		// addChild.setLeft(handleHorizontal(160);
		topButtons.addChild(addChild);

		/*
		 * IMenuButton addSibling = new IMenuButton("Add Sibling",
		 * getAddSiblingMenu()); addSibling.setWidth((75));
		 * 
		 * addSibling.setLeft((80)); // addSibling.setLeft(handleHorizontal(5);
		 * 
		 * topButtons.addChild(addSibling);
		 */

		IButton delete = new IButton("Delete Node");
		delete.setLeft((85));
		delete.setWidth((80));

		// delete.setLeft(handleHorizontal(300);

		delete.addClickHandler(new ClickHandler() {

			public void onClick(ClickEvent event) {
				deleteNode();
			}
		});

		topButtons.addChild(delete);
		return topButtons;
	}

	TreeGrid treeGrid = null;
	TreeNode rootNode = null;

	private TreeGrid getTree() {
		// EmployeeXmlDS employeesDS = EmployeeXmlDS.getInstance();
		rootNode = new TreeNode();
		rootNode.setAttribute(Name, "Root");
		rootNode.setAttribute(Name1, "Root1");
		rootNode.setAttribute(Type, Sequence);
		rootNode.setAttribute(Min, 1);
		rootNode.setAttribute(Max, 1);

		Tree tree = new Tree();
		tree.setModelType(TreeModelType.PARENT);
		tree.setRootValue(1);
		tree.setNameProperty("Name1");
		tree.setOpenProperty("isOpen");
		tree.setData(new TreeNode[] { rootNode });

		treeGrid = new TreeGrid();
		treeGrid.setData(tree);
		treeGrid.setCanReorderRecords(true);
		treeGrid.setCanAcceptDroppedRecords(true);

		// treeGrid.setCanDragResize(true);
		treeGrid.setCanEdit(true);
		treeGrid.setLoadDataOnDemand(false);
		treeGrid.setWidth(handleHorizontal(870));
		treeGrid.setHeight(handleVertical(290));
		// treeGrid.setDataSource(employeesDS);
		treeGrid.setNodeIcon("http://xml-it.appspot.com/icons/16/person.png");
		treeGrid.setFolderIcon("http://xml-it.appspot.com/icons/16/person.png");
		treeGrid.setShowOpenIcons(false);
		treeGrid.setShowDropIcons(false);
		treeGrid.setClosedIconSuffix("");
		// treeGrid.setAutoFetchData(true);

		TreeGridField nameField = new TreeGridField("Name", handleHorizontal(
				650, 900));
		nameField.setCanSort(false);
		RegExpValidator elementName = new RegExpValidator();
		elementName.setErrorMessage("Invalid name for XML element");
		elementName.setExpression("^([a-zA-Z])+([a-zA-Z0-9\\-_\\.])*");

		nameField.setValidators(elementName);

		TreeGridField typeField = new TreeGridField(Type, 60);
		typeField.setCanSort(false);

		TreeGridField minField = new TreeGridField(Min, 30);
		minField.setCanSort(false);

		TreeGridField maxField = new TreeGridField(Max, 30);
		maxField.setCanSort(false);

		maxField.setType(ListGridFieldType.INTEGER);
		minField.setType(ListGridFieldType.INTEGER);

		TreeGridField prefix = new TreeGridField(Prefix, 40);
		prefix.setCanSort(false);

		TreeGridField suffix = new TreeGridField(Suffix, 40);
		suffix.setCanSort(false);
		typeField.setValueMap(Sequence, Choice, Simple);

		treeGrid.setFields(nameField, typeField, minField, maxField, prefix,
				suffix);
		treeGrid.addSelectionChangedHandler(new SelectionChangedHandler() {

			@Override
			public void onSelectionChanged(SelectionEvent event) {
				TreeNode selection = (TreeNode) treeGrid.getSelectedRecord();
				if (selection == null)
					return;
				handleSelection(selection);

			}

		});

		treeGrid.selectRecord(rootNode);
		// handleSelection(rootNode);
		return treeGrid;
	}

	protected void handleSelection(TreeNode selection) {
		if (Simple.equals(selection.getAttribute(Type))) {
			nonleaf.hide();
			leafTabs.show();

			delimiterItem.hide();
			advance.hide();
			lookahead.hide();
			not.hide();
			/*
			 * prefixItem.hide(); suffixItem.hide();
			 */regexItem.show();
			addChildMenu.disable();
			selectTab(selection);
		} else if (Sequence.equals(selection.getAttribute(Type))) {
			nonleaf.show();
			leafTabs.hide();
			delimiterItem.show();
			advance.show();
			// lookahead.show();
			/*
			 * prefixItem.show(); suffixItem.show();
			 */regexItem.hide();
			addChildMenu.enable();
		} else {
			nonleaf.hide();
			leafTabs.hide();

			advance.hide();
			lookahead.hide();
			not.hide();

			delimiterItem.hide();
			/*
			 * prefixItem.hide(); suffixItem.hide();
			 */regexItem.hide();
			addChildMenu.enable();
		}
		delimiterItem.setValue(selection.getAttribute(Delimiter) == null ? ""
				: selection.getAttribute(Delimiter));
		lookahead.setValue(selection.getAttribute(Lookahead) == null ? ""
				: selection.getAttribute(Lookahead));
		allowdVals.setValue(selection.getAttribute(AllowedValues) == null ? ""
				: selection.getAttribute(AllowedValues));
		charsItem.setValue(selection.getAttribute(AllowedChars) == null ? ""
				: selection.getAttribute(AllowedChars));
		String type = getAllowedCharsValsOrNull(selection
				.getAttribute(AllowedChars));
		charsItemType.setValue(type == null ? "" : type);
		min.setValue(selection.getAttribute(minLength) == null ? "" : selection
				.getAttribute(minLength));
		max.setValue(selection.getAttribute(maxLength) == null ? "" : selection
				.getAttribute(maxLength));
		if (selection.getAttribute(Lookahead) != null
				&& !selection.getAttribute(Lookahead).equals("")) {
			lookahead.show();
			not.show();
			advance.setValue(true);
		} else {
			lookahead.hide();
			not.hide();
			advance.setValue(false);
		}
		not.setValue(selection.getAttributeAsBoolean(Not));
		if ((Boolean) selection.getAttributeAsBoolean(Not)) {
			lookahead.setTitle(mustNotFollow);
		}
		/*
		 * prefixItem.setValue(selection.getAttribute("Prefix") == null ? "" :
		 * selection.getAttribute("Prefix"));
		 * suffixItem.setValue(selection.getAttribute("Suffix") == null ? "" :
		 * selection.getAttribute("Suffix"));
		 */regexItem.setValue(selection.getAttribute("Regex") == null ? ""
				: selection.getAttribute("Regex"));

		String reg = regexItem.getValueAsString();
		String[] categoryAndExpression = getCategoryAndExpression(reg);
		if (categoryAndExpression != null) {
			divisionItem.setValue(categoryAndExpression[0]);
			departmentItem.setValue(categoryAndExpression[1]);
		}

	}

	private void selectTab(TreeNode selection) {
		String regex = selection.getAttribute(Regex);
		String allowedVals = selection.getAttribute(AllowedValues);
		String allowedChars = selection.getAttribute(AllowedChars);

		if (regex != null && !"".equals(regex)) {
			leafTabs.selectTab("i1");
		}
		if (allowedVals != null && !"".equals(allowedVals)) {
			leafTabs.selectTab("i2");
		}
		if (allowedChars != null && !"".equals(allowedChars)) {
			leafTabs.selectTab("i3");
		}

	}

	TextAreaItem xmlAreaItem = null;
	TextAreaItem textAreaItem = null;

	private void createScreen() {
		Img moveImg = new Img("http://xml-it.appspot.com/icons/ajaxloader.gif");
		moveImg.setTop(handleVertical(200));
		moveImg.setLeft(handleHorizontal(500));
		moveImg.show();
		final VLayout main = new VLayout();
		main.setShowEdges(true);
		main.setShowResizeBar(true);

		main.setWidth(handleHorizontal(1200));
		main.setHeight(handleVertical(600));
		main.setAlign(VerticalAlignment.CENTER);
		HLayout topButtons = new HLayout();
		topButtons.setShowResizeBar(true);

		// topButtons.setShowEdges(true);
		topButtons.setWidth(handleHorizontal(1200));
		topButtons.setHeight(handleVertical(50));

		IMenuButton applyExample = new IMenuButton("Apply Examples",
				getExamplesMenu());
		applyExample.setWidth((120));
		applyExample.setHeight((25));
		applyExample.setTop(handleVertical(10));
		applyExample.setLeft(handleHorizontal(10));
		// addChild.setTop(handleVertical(5);
		// addChild.setLeft(handleHorizontal(160);
		topButtons.addChild(applyExample);

		Label label = new Label();
		label.setHeight(handleVertical(30));
		label.setAlign(Alignment.CENTER);
		label.setValign(VerticalAlignment.CENTER);
		label.setWrap(false);
		// label.setIcon("icons/16/approved.png");
		// label.setShowEdges(true);
		label.setContents("<font size=\"6\" color=\"red\"><b>XML</b></font>"
				+ "<font size=\"6\" color=\"black\"><b>&gt;/&lt;</b></font>"
				+ "<font size=\"6\" color=\"red\"><b>it</b></font>"
				+ "<font size=\"6\" color=\"red\"><b>!</b></font>");
		topButtons.addChild(label);
		label.setLeft(handleHorizontal(550));

		main.addChild(topButtons);

		HLayout treeLayout = new HLayout();
		treeLayout.setShowResizeBar(true);

		// treeLayout.setShowEdges(true);
		treeLayout.setWidth(handleHorizontal(1180));
		treeLayout.setHeight(handleVertical(300));
		treeLayout.setTop(handleVertical(50));
		main.addChild(getTabs(treeLayout));
		treeLayout.addChild(getTree());
		treeLayout.addChild(getLeafTabs());
		leafTabs.hide();
		treeLayout.addChild(getProperties());
		nonleaf.show();
		HLayout buttons = getButtons();
		treeLayout.addChild(buttons);

		// treeLayout.addChild(getTabs());
		HLayout editorLayout = new HLayout();
		editorLayout.setShowResizeBar(true);

		editorLayout.setShowEdges(true);
		editorLayout.setWidth(handleHorizontal(1200));
		editorLayout.setHeight(handleVertical(200));
		editorLayout.setTop(handleVertical(400));
		main.addChild(editorLayout);

		DynamicForm textForm = new DynamicForm();
		textForm.setTop(handleVertical(10));
		textAreaItem = new TextAreaItem();
		textAreaItem.setWrap(TextAreaWrap.HARD);
		textAreaItem.setTitle("Text");
		textAreaItem.setWidth(handleHorizontal(500));
		textAreaItem.setHeight(handleVertical(190));
		textAreaItem.setTitleOrientation(TitleOrientation.TOP);
		DynamicForm xmlForm = new DynamicForm();
		xmlForm.setTop(handleVertical(10));
		xmlForm.setLeft(handleHorizontal(700));
		xmlAreaItem = new TextAreaItem();
		xmlAreaItem.setWrap(TextAreaWrap.HARD);
		xmlAreaItem.setTitle("XML");
		xmlAreaItem.setWidth(handleHorizontal(500));
		xmlAreaItem.setHeight(handleVertical(190));
		xmlAreaItem.setTitleOrientation(TitleOrientation.TOP);

		textForm.setFields(textAreaItem);
		editorLayout.addChild(textForm);

		VStack moveControls = new VStack(10);
		moveControls.setWidth(handleHorizontal(32));
		moveControls.setHeight(handleVertical(74));
		moveControls.setLayoutAlign(Alignment.CENTER);

		TransferImgButton rightArrow = new TransferImgButton(
				TransferImgButton.RIGHT, new ClickHandler() {
					public void onClick(ClickEvent event) {
						unmarshelService.unmarshel(
								textAreaItem.getValue() + "", TreeToStruct
										.getStruct(treeGrid, rootNode, null),
								new AsyncCallback<String>() {

									@Override
									public void onFailure(Throwable caught) {
										if (caught instanceof UnmarshalException) {
											String val = (String) textAreaItem
													.getValue();
											String after = val
													.replace("\n", "\r\n")
													.substring(
															0,
															((UnmarshalException) caught).lastPossition);
											int count = after.length()
													- after.replace("\r\n",
															"\n").length();
											textAreaItem
													.setSelectionRange(
															0,
															((UnmarshalException) caught).lastPossition
																	- count);
											xmlAreaItem.setValue("");

											com.google.gwt.user.client.Window
													.alert("Parsing failed. Managed to parse only the selected text. Last position:"
															+ ((UnmarshalException) caught).lastPossition);
										} else {
											com.google.gwt.user.client.Window
													.alert("Operation failed.");
										}
										GWT.log("", caught);

									}

									@Override
									public void onSuccess(String result) {
										xmlAreaItem.setValue(result);

									}
								});
					}

				});
		moveControls.addMember(rightArrow);

		TransferImgButton leftArrow = new TransferImgButton(
				TransferImgButton.LEFT, new ClickHandler() {
					public void onClick(ClickEvent event) {
						unmarshelService.marshel(xmlAreaItem.getValue() + "",
								TreeToStruct
										.getStruct(treeGrid, rootNode, null),
								new AsyncCallback<String>() {

									@Override
									public void onFailure(Throwable caught) {
										com.google.gwt.user.client.Window
												.alert("Can't perform operation: "
														+ caught);
										GWT.log("", caught);
									}

									@Override
									public void onSuccess(String result) {
										textAreaItem.setValue(result);

									}
								});

					}
				});
		moveControls.addMember(leftArrow);
		moveControls.setTop(handleVertical(80));
		moveControls.setLeft(handleHorizontal(585));

		editorLayout.addChild(moveControls);

		xmlForm.setFields(xmlAreaItem);
		editorLayout.addChild(xmlForm);
		treeGrid.setContextMenu(getTreeMenu());

		main.draw();

		delimiterItem.hide();
		advance.hide();
		lookahead.hide();
		not.hide();
		/*
		 * prefixItem.hide(); suffixItem.hide();
		 */regexItem.hide();
		DOM.removeChild(RootPanel.getBodyElement(),
				DOM.getElementById("loading"));

	}

	private TabSet getLeafTabs() {
		leafTabs = new TabSet();
		leafTabs.setTabBarThickness(30);
		leafTabs.setTop(handleVertical(10));
		leafTabs.setWidth(/* handleHorizontal */(250));
		leafTabs.setHeight(handleVertical(180));

		leafTabs.setLeft(handleHorizontal(880));
		Tab regex = new Tab("Expression");
		regex.setID("i1");
		handleRegex(regex);
		Tab vals = new Tab("Allowed<br />Values");
		vals.setID("i2");

		handleVals(vals);
		Tab chars = new Tab("Allowed<br />Chars");
		chars.setID("i3");

		handleChars(chars);
		leafTabs.setTabs(chars, vals, regex);

		return leafTabs;

	}

	SelectItem charsItemType = null;

	TextItem charsItem = null;
	TextItem min = null;
	TextItem max = null;

	private void handleChars(Tab chars) {
		DynamicForm form = new DynamicForm();

		charsItem = new TextItem();
		charsItem.setTitle("Allowed Characters");
		charsItem.setRequired(true);

		charsItem.addChangedHandler(new ChangedHandler() {

			@Override
			public void onChanged(ChangedEvent event) {
				treeGrid.getSelectedRecord().setAttribute(AllowedChars,
						charsItem.getValue());
				if (charsItem.getValue() != null
						&& !"".equals(charsItem.getValue())) {
					treeGrid.getSelectedRecord().setAttribute(AllowedValues,
							(String) null);
					treeGrid.getSelectedRecord().setAttribute(Regex,
							(String) null);

					allowdVals.setValue("");
					regexItem.setValue("");

				}

			}

		});

		charsItemType = new SelectItem();
		charsItemType.setName("type");
		charsItemType.setTitle("Type");
		charsItemType.setValueMap("Alphabetic", "Numeric", "Alphanumeric");
		charsItemType.addChangeHandler(new ChangeHandler() {
			public void onChange(ChangeEvent event) {
				String selectedItem = (String) event.getValue();
				treeGrid.getSelectedRecord().setAttribute(AllowedChars,
						allowedCharsVals.get(selectedItem));
				charsItem.setValue(allowedCharsVals.get(selectedItem));
				charsItem.redraw();

				treeGrid.getSelectedRecord().setAttribute(AllowedCharsType,
						selectedItem);

			}
		});

		min = new TextItem();
		min.setTitle("Minimum Length");
		min.setRequired(true);

		min.addChangedHandler(new ChangedHandler() {

			@Override
			public void onChanged(ChangedEvent event) {
				treeGrid.getSelectedRecord().setAttribute(minLength,
						min.getValue());

			}

		});

		max = new TextItem();
		max.setTitle("Maximum Length");
		max.setRequired(true);

		max.addChangedHandler(new ChangedHandler() {

			@Override
			public void onChanged(ChangedEvent event) {
				treeGrid.getSelectedRecord().setAttribute(maxLength,
						max.getValue());
			}

		});
		form.setFields(charsItemType, charsItem, min, max);
		chars.setPane(form);

	}

	TextAreaItem allowdVals = null;

	private void handleVals(Tab vals) {

		DynamicForm form = new DynamicForm();
		allowdVals = new TextAreaItem();
		allowdVals.setWrap(TextAreaWrap.HARD);
		allowdVals.setTitle("Allowed values (each line is a value)");
		// textAreaItem.setWidth(handleHorizontal(1100));
		// textAreaItem.setHeight(handleVertical(300));
		allowdVals.addChangedHandler(new ChangedHandler() {

			@Override
			public void onChanged(ChangedEvent event) {
				treeGrid.getSelectedRecord().setAttribute(AllowedValues,
						allowdVals.getValue());
				if (allowdVals.getValue() != null
						&& !"".equals(allowdVals.getValue())) {
					treeGrid.getSelectedRecord().setAttribute(Regex,
							(String) null);
					treeGrid.getSelectedRecord().setAttribute(maxLength,
							(String) null);
					treeGrid.getSelectedRecord().setAttribute(minLength,
							(String) null);
					treeGrid.getSelectedRecord().setAttribute(AllowedChars,
							(String) null);

					regexItem.setValue("");
					min.setValue("");
					max.setValue("");
					charsItem.setValue("");
					charsItemType.setValue("");

				}

			}

		});
		form.setFields(allowdVals);
		vals.setPane(form);
	}

	private void handleRegex(Tab regex) {
		final DynamicForm form = new DynamicForm();
		divisionItem = new SelectItem();
		regexItem = new TextItem();

		divisionItem.setName("category");
		divisionItem.setTitle("Category");
		divisionItem.setValueMap(categoryMap.keySet().toArray(
				new String[categoryMap.keySet().size()]));
		divisionItem.addChangeHandler(new ChangeHandler() {
			public void onChange(ChangeEvent event) {
				String selectedItem = (String) event.getValue();
				selected = categoryMap.get(selectedItem);
				form.getField("expression").setValueMap(
						selected.keySet().toArray(new String[selected.size()]));
			}
		});

		departmentItem = new SelectItem();
		departmentItem.setName("expression");
		departmentItem.setTitle("Expression");
		// departmentItem.setAddUnknownValues(false);

		departmentItem.addChangeHandler(new ChangeHandler() {
			public void onChange(ChangeEvent event) {
				String selectedItem = (String) event.getValue();
				if (selected != null) {
					regexItem.setValue(selected.get(selectedItem));
					treeGrid.getSelectedRecord().setAttribute(Regex,
							regexItem.getValue());
				}
			}
		});

		regexItem.setTitle("Regular Expression");
		regexItem.setRequired(true);

		regexItem.addChangedHandler(new ChangedHandler() {

			@Override
			public void onChanged(ChangedEvent event) {
				treeGrid.getSelectedRecord().setAttribute(Regex,
						regexItem.getValue());
				if (regexItem.getValue() != null
						&& !"".equals(regexItem.getValue())) {
					treeGrid.getSelectedRecord().setAttribute(AllowedValues,
							(String) null);
					treeGrid.getSelectedRecord().setAttribute(maxLength,
							(String) null);
					treeGrid.getSelectedRecord().setAttribute(minLength,
							(String) null);
					treeGrid.getSelectedRecord().setAttribute(AllowedChars,
							(String) null);

					allowdVals.setValue("");
					min.setValue("");
					max.setValue("");
					charsItem.setValue("");
					charsItemType.setValue("");

				}

			}

		});
		form.setItems(divisionItem, departmentItem, regexItem);
		regex.setPane(form);

	}

	private TabSet getTabs(HLayout layout) {
		TabSet tabSet = new TabSet();
		tabSet.setHeight(handleVertical(350));
		tabSet.setWidth(handleHorizontal(1210));
		Tab treeTab = new Tab("Tree View");
		treeTab.setPane(layout);
		Tab xsdTab = new Tab("XSD View");
		DynamicForm textForm = new DynamicForm();
		textForm.setTop(handleVertical(10));
		final TextAreaItem textAreaItem = new TextAreaItem();
		textAreaItem.setWrap(TextAreaWrap.HARD);
		textAreaItem.setTitle("XSD");
		textAreaItem.setWidth(handleHorizontal(1100));
		textAreaItem.setHeight(handleVertical(300));
		textForm.setFields(textAreaItem);
		xsdTab.setPane(textForm);

		tabSet.setTabs(treeTab, xsdTab);
		tabSet.setTop(handleVertical(50));

		tabSet.addTabSelectedHandler(new TabSelectedHandler() {

			@Override
			public void onTabSelected(TabSelectedEvent event) {
				Storage stockStore = Storage.getLocalStorageIfSupported();
				stockStore.setItem("XSD", textAreaItem.getValueAsString());

				if ("XSD View".equals(event.getTab().getTitle())) {
					unmarshelService.getXSD(
							TreeToStruct.getStruct(treeGrid, rootNode, null),
							new AsyncCallback<String>() {

								@Override
								public void onSuccess(String result) {
									textAreaItem.setValue(result);
								}

								@Override
								public void onFailure(Throwable caught) {
									com.google.gwt.user.client.Window
											.alert("Can't perform operation: "
													+ caught);
									GWT.log("", caught);
								}
							});
				} else {
					if (textAreaItem.getValue() != null) {
						unmarshelService.getStruct(
								textAreaItem.getValue() + "",
								new AsyncCallback<Struct>() {

									@Override
									public void onSuccess(Struct result) {
										// TreeNode node = new TreeNode();
										// treeGrid.getTree().setRoot(node);
										treeGrid.getTree().removeList(
												treeGrid.getTree().getChildren(
														rootNode));
										treeGrid.redraw();
										TreeToStruct.getTreeNode(result,
												treeGrid, rootNode);
										treeGrid.redraw();
										// treeGrid.getTree().setRoot(newRoot);

									}

									@Override
									public void onFailure(Throwable caught) {
										com.google.gwt.user.client.Window
												.alert("The XSD is invalid. Can't create Tree.");
										GWT.log("", caught);

									}
								});
					}
				}
				treeGrid.selectRecord(rootNode);

			}
		});
		return tabSet;

	}

	private Menu getAddChildMenu() {
		Menu mainMenu = new Menu();

		MenuItem addChildSeq = new MenuItem();
		addChildSeq.setTitle("Sequance");
		addChildSeq
				.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler() {
					public void onClick(MenuItemClickEvent event) {
						TreeNode node = newChild(Sequence);
						node.setAttribute(Type, Sequence);
						node.setAttribute(Min, 1);
						node.setAttribute(Max, 1);

					}
				});
		mainMenu.addItem(addChildSeq);

		MenuItem addChildChoce = new MenuItem();
		addChildChoce.setTitle("Choice");
		addChildChoce
				.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler() {
					public void onClick(MenuItemClickEvent event) {
						TreeNode node = newChild(Choice);
						node.setAttribute("Type", Choice);
						node.setAttribute("Min", 1);
						node.setAttribute("Max", 1);

					}
				});
		mainMenu.addItem(addChildChoce);

		MenuItem addChildSimple = new MenuItem();
		addChildSimple.setTitle("Simple");
		addChildSimple
				.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler() {
					public void onClick(MenuItemClickEvent event) {
						TreeNode node = newChild(Simple);
						node.setAttribute(Type, Simple);
						node.setAttribute(Min, 1);
						node.setAttribute(Max, 1);
					}
				});
		mainMenu.addItem(addChildSimple);

		return mainMenu;

	}

	private Menu getExamplesMenu() {
		Menu mainMenu = new Menu();

		for (int i = 1; i < 7; i++) {
			final int num = i;
			MenuItem addChildSeq = new MenuItem();
			addChildSeq.setTitle("Example " + i);
			addChildSeq
					.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler() {
						public void onClick(MenuItemClickEvent event) {
							unmarshelService.getExampleContainer(num,
									new AsyncCallback<ExampleContainer>() {

										@Override
										public void onFailure(Throwable caught) {
											com.google.gwt.user.client.Window
													.alert("Can't perform operation: "
															+ caught);
											GWT.log("", caught);

										}

										@Override
										public void onSuccess(
												ExampleContainer result) {
											treeGrid.getTree().removeList(
													treeGrid.getTree()
															.getChildren(
																	rootNode));
											TreeToStruct.getTreeNode(
													result.getStruct(),
													treeGrid, rootNode);
											if (num != 3)
											textAreaItem.setValue(result
													.getMessage());
											else
											{
												Storage stockStore = Storage.getLocalStorageIfSupported();
												textAreaItem.setValue(stockStore.getItem("XSD"));
												
												
											}
											treeGrid.getTree().openFolder(
													(TreeNode) rootNode);
											treeGrid.selectRecord(rootNode);
										}
									});
						}
					});
			mainMenu.addItem(addChildSeq);

		}

		return mainMenu;

	}

	/*
	 * private Menu getAddSiblingMenu() { Menu mainMenu = new Menu();
	 * 
	 * MenuItem addChildSeq = new MenuItem(); addChildSeq.setTitle("Sequance");
	 * addChildSeq .addClickHandler(new
	 * com.smartgwt.client.widgets.menu.events.ClickHandler() { public void
	 * onClick(MenuItemClickEvent event) { TreeNode node = newSibling(Sequence);
	 * if (node == null) return; node.setAttribute(Type, Sequence);
	 * node.setAttribute(Min, 1); node.setAttribute(Max, 1);
	 * 
	 * } }); mainMenu.addItem(addChildSeq);
	 * 
	 * MenuItem addChildChoce = new MenuItem();
	 * addChildChoce.setTitle("Choice"); addChildChoce .addClickHandler(new
	 * com.smartgwt.client.widgets.menu.events.ClickHandler() { public void
	 * onClick(MenuItemClickEvent event) { TreeNode node = newSibling(Choice);
	 * if (node == null) return; node.setAttribute("Type", Choice);
	 * node.setAttribute("Min", 1); node.setAttribute("Max", 1);
	 * 
	 * } }); mainMenu.addItem(addChildChoce);
	 * 
	 * MenuItem addChildSimple = new MenuItem();
	 * addChildSimple.setTitle("Simple"); addChildSimple .addClickHandler(new
	 * com.smartgwt.client.widgets.menu.events.ClickHandler() { public void
	 * onClick(MenuItemClickEvent event) { TreeNode node = newSibling(Simple);
	 * if (node == null) return; node.setAttribute(Type, Simple);
	 * node.setAttribute(Min, 1); node.setAttribute(Max, 1); } });
	 * mainMenu.addItem(addChildSimple);
	 * 
	 * return mainMenu;
	 * 
	 * }
	 */

	Menu addChildMenu = null;

	private Menu getTreeMenu() {
		Menu mainMenu = new Menu();
		MenuItem addChild = new MenuItem("Add Child");
		addChildMenu = getAddChildMenu();
		addChild.setSubmenu(addChildMenu);

		/*
		 * addChild.setTitle("Add Child"); addChild.addClickHandler(new
		 * com.smartgwt.client.widgets.menu.events.ClickHandler() { public void
		 * onClick(MenuItemClickEvent event) { newChild(); } });
		 */
		mainMenu.addItem(addChild);
		MenuItem copyMenu = new MenuItem("Copy");
		mainMenu.addItem(copyMenu);
		copyMenu.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler() {
			public void onClick(MenuItemClickEvent event) {
				copy();
			}

		});

		MenuItem pasteMenu = new MenuItem("Paste");
		mainMenu.addItem(pasteMenu);
		pasteMenu
				.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler() {
					public void onClick(MenuItemClickEvent event) {
						paste();
					}

				});
		// MenuItem addSibling = new MenuItem("Add Sibling");
		// addSibling.setSubmenu(getAddSiblingMenu());
		/*
		 * addSibling.setTitle("Add Sibling"); addSibling .addClickHandler(new
		 * com.smartgwt.client.widgets.menu.events.ClickHandler() { public void
		 * onClick(MenuItemClickEvent event) { newSibling(); } });
		 */
		// mainMenu.addItem(addSibling);

		MenuItem delete = new MenuItem();
		delete.setTitle("Delete Node");
		delete.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler() {
			public void onClick(MenuItemClickEvent event) {
				deleteNode();
			}

		});
		mainMenu.addItem(delete);

		return mainMenu;
	}

	private TreeNode newChild(String type) {
		TreeNode newNode = new TreeNode();
		TreeNode selected = (TreeNode) treeGrid.getSelectedRecord();
		if (selected == null)
			selected = rootNode;
		newNode.setAttribute(Name, getUniqueName(type, selected));
		treeGrid.getTree().add(newNode, selected);
		treeGrid.getTree().openFolder(selected);
		return newNode;

	}

	private void copy() {
		copy = (TreeNode) treeGrid.getSelectedRecord();

	}

	private void paste() {
		if (copy != null) {
			TreeNode toPaste = clone(copy);
			TreeNode selected = (TreeNode) treeGrid.getSelectedRecord();
			treeGrid.getTree().add(toPaste, selected);
			treeGrid.getTree().openFolder(selected);
		}

	}

	private TreeNode clone(TreeNode copy2) {
		TreeNode result = new TreeNode();
		for (String attr : copy2.getAttributes()) {
			if (!attr.startsWith("_") && !attr.startsWith("$"))
				result.setAttribute(attr, copy2.getAttribute(attr));
		}
		for (TreeNode child : treeGrid.getTree().getChildren(copy2)) {
			treeGrid.getTree().add(clone(child), result);
		}

		return result;
	}

	/*
	 * private TreeNode newSibling(String type) { if
	 * (!"Root1".equals(treeGrid.getSelectedRecord().getAttribute("Name1"))) {
	 * 
	 * TreeNode newNode = new TreeNode(); TreeNode selected = (TreeNode)
	 * treeGrid.getSelectedRecord(); if (selected == null) selected = rootNode;
	 * TreeNode parent = treeGrid.getTree().getParent(selected);
	 * newNode.setAttribute(Name, getUniqueName(type, parent)); int i = 0; for
	 * (TreeNode syb : treeGrid.getTree().getChildren(parent)) { if
	 * (syb.equals(parent)) { break; } i++; } treeGrid.getTree().add(newNode,
	 * parent, i); return newNode; } return null; }
	 */

	private String getUniqueName(String type, TreeNode parent) {
		ArrayList names = new ArrayList();
		TreeNode[] nodes = treeGrid.getTree().getChildren(parent);
		for (TreeNode node : nodes) {
			names.add(node.getAttribute(Name));
		}
		String newName = "New" + type;
		int count = 1;
		while (names.contains(newName + count)) {
			count++;
		}

		return newName + count;
	}

	private void deleteNode() {
		if (!"Root1".equals(treeGrid.getSelectedRecord().getAttribute("Name1")))
			treeGrid.removeData(treeGrid.getSelectedRecord());
	}

	private int handleVertical(double num) {
		return (int) ((num / 820) * getAvailHeight());
	}

	private int handleHorizontal(double num, double proportion) {
		return (int) ((proportion / 1230) * getAvailWidth() - proportion + num);
	}

	private int handleHorizontal(double num) {
		return (int) ((num / 1230) * getAvailWidth());
	}

	public static native String getAvailHeightNative() /*-{
		var screenHeight = screen.availHeight + "";
		return screenHeight;
	}-*/;

	public static native String getAvailWidthNative() /*-{
		var screenWidth = screen.availWidth + "";
		return screenWidth;
	}-*/;

	public static double getAvailHeight() {
		double result = (double) Double.parseDouble(getAvailHeightNative());
		if (result < 768)
			return 768;
		return result;

	}

	public static double getAvailWidth() {
		double result = (double) Double.parseDouble(getAvailWidthNative());
		if (result < 1024)
			return 1024;
		return result;
	}

}